home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d12
/
v9n20.arc
/
PCSORT.ASM
< prev
next >
Wrap
Assembly Source File
|
1990-10-29
|
105KB
|
3,311 lines
;--------------------------------------------------;
; PCSORT * PC Magazine * Michael J. Mefford ;
; ;
; Text file column sort utility. ;
;--------------------------------------------------;
_TEXT SEGMENT PUBLIC 'CODE'
ASSUME CS:_TEXT,DS:_TEXT,ES:_TEXT,SS:_TEXT
ORG 100H
START: JMP MAIN
; DATA AREA
; ---------
COLOR_ATTRIBS STRUC
B DB 71H ;Blue on lt. gray
W DB 17H ;Lt. gray on blue
C DB 31H ;Blue on cyan
COLOR_ATTRIBS ENDS
COLOR COLOR_ATTRIBS <>
COLOR_ATTR COLOR_ATTRIBS <>
MONO_ATTR COLOR_ATTRIBS <70H, 07H, 70H>
BORDER_FLAG DB 0 ; =1 to disable.
SIGNATURE DB CR,SPACE,SPACE,SPACE,CR,LF
COPYRIGHT DB "PCSORT 1.0 (c) 1990 Ziff Communications Co. ",CR,LF
PROGRAMMER DB "PC Magazine ",BOX," Michael J. Mefford",LF
CRLF DB CR,LF
SYNTAX LABEL BYTE
DB "Syntax: PCSORT [filename] [options]",CR,LF,LF
DB "/C Case sensitive sort; default=Case insensitive",CR,LF
DB "/S n n=size of record in lines (1-9); default=1",CR,LF
DB "/P n n=sort priority (1-9); default=1",CR,LF
DB "/R sort current priority in reverse order",CR,LF
DB " default order is ascending",CR,LF
DB "/N Numeric sort current priority; default=Alphanumeric",CR,LF
DB "/L[n] Line sort; n=record sort line (1-9); default=1",CR,LF
DB " default sort is a line sort",CR,LF
DB "/nn [xx [y]] Block or column sort",CR,LF
DB " nn=start column; xx=width; y=sort line (1-9)",CR,LF
DB " defaults: nn=1; xx=start column to end of line; y=1",CR,LF
DB "/W [+|-] n Word sort; n=word count",CR,LF
DB " minus is count from end of record; default is plus 1",CR,LF
DB " PcSort can be used as a filter. For example,",CR,LF
DB " DIR | PCSORT /P1 W2 /P2 W1 > EXAMPLE",CR,LF
DB " creates an EXAMPLE file of a DIR sorted by extension and name.",CR,LF
DB "$",CTRL_Z
TAB EQU 9
CR EQU 13
LF EQU 10
CTRL_Z EQU 26
SPACE EQU 32
BOX EQU 254
FF EQU 12
SHIFT_KEYS EQU 3
ESC_SCAN EQU 1
Y_SCAN EQU 15H
N_SCAN EQU 31H
F1_SCAN EQU 3BH
F2_SCAN EQU 3CH
F3_SCAN EQU 3DH
F4_SCAN EQU 3EH
F5_SCAN EQU 3FH
F6_SCAN EQU 40H
F7_SCAN EQU 41H
F8_SCAN EQU 42H
F9_SCAN EQU 43H
F10_SCAN EQU 44H
KB_FLAG EQU 17H
UP_SCAN EQU 48H
DOWN_SCAN EQU 50H
LEFT_SCAN EQU 4BH
RIGHT_SCAN EQU 4DH
PGUP_SCAN EQU 49H
PGDN_SCAN EQU 51H
BS_SCAN EQU 0EH
DEL_SCAN EQU 53H
HOME_SCAN EQU 47H
END_SCAN EQU 4FH
ENTER_SCAN EQU 1CH
TAB_SCAN EQU 0FH
CTRL_HOME_SCAN EQU 77H
CTRL_END_SCAN EQU 75H
SHIFT_F5 EQU 58H
SHIFT_F6 EQU 59H
SHIFT_F9 EQU 5CH
SHIFT_F10 EQU 5DH
ALT_F1 EQU 68H
COMMA EQU ","
DECIMAL_POINT EQU "."
PLUS_SIGN EQU "+"
MINUS_SIGN EQU "-"
NOTE EQU 1046 ; C
SCREEN_COLOR DB ?
CRT_MODE EQU 49H
CRT_COLS EQU 4AH
CRT_ROWS EQU 84H
COLUMNS DW ?
CRT_WIDTH DW ?
CRT_START DW ?
STATUS_REG DW 3BAH
VIDEO_SEG DW 0B000H
ROWS DB 24
LISTING_LEN DW ?
SWITCH_CHARS DB "PRL+"
DB "WSNC"
SWITCH_LEN EQU $ - SWITCH_CHARS
SWITCH_DISPATCH DW SW_PRIORITY, SW_DIRECTION, SW_LINE, SW_BLOCK
DW SW_WORD, SW_RECORDS, SW_NUMERIC, SW_CASE
CASE DB 5FH ;Capitalize; =FFh if case sensitive.
JB_CODE EQU 72H
JA_CODE EQU 77H
STDIN_FLAG DB 1 ; =1 if redirection of input.
MODIFY_FLAG DB 0 ; =1 if file modified.
INDEX_SEG DW ?
TEXT_SEG DW ?
MEM_TOP_OFF DW ?
MEM_TOP_SEG DW ?
FILENAME DW ?
FILE_CURSOR DW ?
EOF_SEG DW ?
EOF_OFF DW ?
LINE_MAX EQU 255
LAST_LINE DW ? ;INDEX offset.
TOP_LINE DW 0 ;INDEX offset.
START_COLUMN DW 0
CURSOR_ROW DB ?
CURSOR_COLUMN DB ?
DISPLAY_COLUMN DW ?
DISPLAY_TEXT DW ?
LONGEST_LINE DW ? ;Length of longest text line.
MARK_INDEX DW ? ;INDEX offset.
MARK_LEFT DW ? ;Display column.
MARK_RIGHT DW ?
INDEX_SIZE EQU 1000H ;64K / 16
READ_SIZE EQU 8000H ;32K
INDEX_REC STRUC
OFF_PTR DW ?
SEG_PTR DW ?
TEXT_LEN DW ? ;Excluding line terminator (CR and/or LF)
LINE_LEN DW ? ;Including line terminator
INDEX_REC ENDS
LINES_PER_REC DB 0
INDEX_PER_REC DW SIZE INDEX_REC
CURRENT_KEY DB 0
ASCEND EQU 0
DESCEND EQU 1
ALPHA_TYPE EQU 0
NUMERIC_TYPE EQU 1
BLOCK_TYPE EQU 0
WORD_TYPE EQU 1
NONE_TYPE EQU 2
LINE_TYPE EQU 3
INACTIVE EQU -1
LINES_REC_MAX EQU 9
KEY_MAX EQU 9
SORT_KEY STRUC
SORT_DIRECTION DB ASCEND
KEY_TYPE DB ALPHA_TYPE
KEY_FIELD DB LINE_TYPE
BLOCK_INDEX DW 0
BLOCK_BEG DW INACTIVE
BLOCK_LEN DW LINE_MAX
WORD_POS DB 1
LINE_INDEX DW 0
SORT_KEY ENDS
KEYS SORT_KEY <>
OTHER_KEYS SORT_KEY KEY_MAX-1 DUP (<,,NONE_TYPE,,,,>)
ALPHANUMERIC DB "Alphanumeric",0
NUMERIC DB "Numeric ",0
ASCENDING DB "Ascending ",0
DESCENDING DB "Descending",0
BLOCK_MSG DB "Block",0
WORD_MSG DB "Word ",0
NONE_MSG DB "None ",0
LINE_MSG DB "Line ",0
FIELD_OFFSET DW BLOCK_MSG, WORD_MSG, NONE_MSG, LINE_MSG
MENU LABEL BYTE
DB " F2 Save F3 New file F4 Sort F5 Lines/rec:",0
DB " F6 Key priority:",0, " F7 ",0
DB " F8 Type:",0, " F9 Field:",0
BLOCK_START DB " F10 Mark block start ",0
WORD_POS_MSG DB " F10 Word position:",0, " ",0
LINE_POS_MSG DB " F10 Mark line ",0
SPACES DB " ",0
END_MSG DB "end ",0
M_DISPATCH DB UP_SCAN, DOWN_SCAN, PGUP_SCAN, PGDN_SCAN
DB LEFT_SCAN, RIGHT_SCAN, HOME_SCAN, END_SCAN
DB HOME_SCAN, END_SCAN, CTRL_HOME_SCAN, CTRL_END_SCAN
DB F2_SCAN, F3_SCAN, F4_SCAN, F5_SCAN
DB F6_SCAN, F7_SCAN, F8_SCAN, F9_SCAN
DB F10_SCAN, SHIFT_F5, SHIFT_F6, SHIFT_F9
DB SHIFT_F10, F1_SCAN, ALT_F1
M_LEN EQU $ - M_DISPATCH
DW UP, DOWN, PGUP, PGDN
DW LEFT, RIGHT, HOME_KEY, END_KEY
DW HOME_KEY, END_KEY, CTRL_HOME, CTRL_END
DW SAVE, NEW_FILE, SORT, LINES_REC
DW PRIORITY, DIRECTION, SORT_TYPE, FIELD_TYPE
DW BLOCKSTART, SH_LINE_REC, SH_PRIORITY, SH_FIELD_TYPE
DW SH_BLOCKSTART, HELP, RESET
NOT_ENOUGH DB " Not enough memory.",0,"$"
FILE_NOT_FOUND DB " File not found.",0
ESC_MSG DB " Esc to Exit",0
FILE_TOO_SMALL DB " File too small.",0
READ_FAIL DB " Read fail.",0
LINE_TOO_LONG DB " Line too long.",0
TOO_MANY_LINES DB " Too many lines.",0
ENTER_FILENAME DB " Enter filename: ",0
NAME_CURSOR EQU $ - ENTER_FILENAME
FILENAME_LEN EQU 80 - NAME_CURSOR - 1
SAVING DB " Saving... ",0
SAVE_FAILED DB " Save failed; Esc to cancel.",0
LOADING_FILE DB " Loading file... ",0
SAVE_FILE DB " Save modified file? Y/N",0
SORTING DB " Sorting...",0
DB " Press Esc to abort",0
; CODE AREA
; ---------
MAIN PROC NEAR
CLD ;String instructions forward.
MOV AH,8
INT 10H
MOV SCREEN_COLOR,AH
MOV BX,-1
MOV AH,4AH ;Allocate memory.
INT 21H
MOV AX,OFFSET STACK_POINTER
ADD AX,15
MOV CL,4
SHR AX,CL
MOV CX,DS
ADD AX,CX
MOV INDEX_SEG,AX
ADD AX,INDEX_SIZE
MOV TEXT_SEG,AX
ADD CX,BX ;Top of memory seg.
ADD AX,READ_SIZE SHR 4
CMP CX,AX
JAE MEMORY_OK
MOV DX,OFFSET NOT_ENOUGH
JMP ERROR_EXIT ;If not enough, exit.
MEMORY_OK: MOV AH,4AH
INT 21H
MOV AX,OFFSET STACK_POINTER
MOV SP,AX ;Set up stack.
SUB CX,TEXT_SEG
MOV AX,CX
XOR DX,DX
MOV BX,READ_SIZE SHR 4
DIV BX
MOV CL,4
SHL DX,CL
MOV MEM_TOP_OFF,DX ;Memory top in reference
MUL BX ; to TEXT_SEG in 32K
ADD AX,TEXT_SEG ; multiples.
MOV MEM_TOP_SEG,AX
XOR BX,BX
MOV AX,4406H ;Input status.
INT 21H
OR AL,AL
JNZ PARSE
MOV STDIN_FLAG,0
CALL VIDEO_SETUP
JMP SHORT PARSE
;---------------
NEXT_FILE: CALL GET_NAME
JC EXIT
PARSE: CALL PARSE_IT
JC ERROR
CMP STDIN_FLAG,1
JZ DO_STDIN
CALL LOAD_FILE
JC NEXT_FILE
JMP SHORT NEXT_KEY
;------------------
DO_STDIN: XOR BX,BX
CALL READ_FILE2
JC ERROR
CALL INDEX
JC ERROR
CALL SORT2
MOV BX,1
CALL SAVE2
JC ERROR
JMP SHORT GOOD_EXIT
;************* Main Loop *************;
NEXT_KEY: CALL UPDATE_MARK
CALL UPDATE_TEXT
CALL DISPLAY_MENU
CALL CLEAR_KEY
MOV DI,OFFSET M_DISPATCH
MOV CX,M_LEN
CALL DISPATCH
JC EXIT
OR AL,AL
JZ NEXT_KEY
CALL MINI_EDIT
JMP NEXT_KEY
;----------------------------------------------;
ERROR_EXIT: CALL PRINT_STRING
MOV AL,1
JMP SHORT TERMINATE2
ERROR: CALL BEEP
MOV AL,1 ;Exit with ERRORLEVEL one.
CMP STDIN_FLAG,1
JZ DONE
CALL CLOSE_SCREEN
JMP SHORT TERMINATE
EXIT: CALL CLOSE_SCREEN
GOOD_EXIT: XOR AL,AL ;ERRORLEVEL zero.
TERMINATE: CMP STDIN_FLAG,1
JZ DONE
TERMINATE2: PUSH AX
MOV DX,OFFSET SIGNATURE
CALL PRINT_STRING
POP AX
DONE: MOV AH,4CH ;Terminate.
INT 21H
MAIN ENDP
; ***************
; * SUBROUTINES *
; ***************
;----------------------------------------------;
MINI_EDIT: CMP AH,CR
JNZ DO_MINI
CALL GET_PARAMS
CALL DOWN
MOV CURSOR_COLUMN,0
MOV START_COLUMN,0
JMP SHORT EDIT_END
DO_MINI: CMP AH,SPACE
JB EDIT_END
PUSH DS
PUSH ES
MOV DL,AH
MOV AL,SIZE INDEX_REC
MUL CURSOR_ROW
ADD AX,TOP_LINE
MOV BX,AX
MOV CL,CURSOR_COLUMN
XOR CH,CH
ADD CX,START_COLUMN
MOV DS,INDEX_SEG
MOV ES,SEG_PTR[BX]
CMP CX,TEXT_LEN[BX]
JAE EDIT_DONE
MOV DI,OFF_PTR[BX]
ADD DI,CX
MOV AL,DL
STOSB
POP ES
POP DS
MOV MODIFY_FLAG,1
CALL RIGHT
JMP SHORT EDIT_END
EDIT_DONE: POP ES
POP DS
EDIT_END: RET
;----------------------------------------------;
UPDATE_MARK: CALL GET_PRIORITY
MOV AL,KEYS.KEY_FIELD[BP]
CMP AL,BLOCK_TYPE
JNZ CK_LINE_TYPE
MOV AX,KEYS.BLOCK_INDEX[BP]
CALL CALC_DISP_REC
MOV MARK_INDEX,AX
MOV AX,KEYS.BLOCK_BEG[BP]
MOV MARK_LEFT,AX
DEC AX
ADD AX,KEYS.BLOCK_LEN[BP]
MOV MARK_RIGHT,AX
JMP SHORT UPDATE_END
CK_LINE_TYPE: CMP AL,LINE_TYPE
JNZ CK_WORD_TYPE
MOV AX,KEYS.LINE_INDEX[BP]
CALL CALC_DISP_REC
MOV MARK_INDEX,AX
MOV MARK_LEFT,0
MOV AX,LONGEST_LINE
DEC AX
MOV MARK_RIGHT,AX
JMP SHORT UPDATE_END
CK_WORD_TYPE: CMP AL,WORD_TYPE
JNZ NO_TYPE
XOR AX,AX
CALL CALC_DISP_REC
PUSH ES
PUSH DS
MOV ES,INDEX_SEG
MOV BX,AX
CALL WORD_ADDRESS
POP DS
JNC CK_MARK_WORD
NO_WORD2: POP ES
JMP SHORT NO_TYPE
CK_MARK_WORD: CMP BX,LAST_LINE
JA NO_WORD2
MARK_WORD: MOV AX,ES:OFF_PTR[BX]
POP ES
MOV MARK_INDEX,BX
SUB DI,AX
MOV MARK_LEFT,DI
SUB SI,AX
MOV MARK_RIGHT,SI
JMP SHORT UPDATE_END
NO_TYPE: MOV MARK_INDEX,INACTIVE
UPDATE_END: RET
;-----------------
; INPUT: AX = index
; OUTPUT: AX = first index offset of first whole record on screen.
CALC_DISP_REC: CALL CALC_ROW
PUSH AX
MOV AX,TOP_LINE
XOR DX,DX
DIV CX
DIV BX
MUL BX
MUL CX
POP DX
ADD AX,DX
CMP AX,TOP_LINE
JAE CALC_END
MOV DX,AX
MOV AX,BX
MUL CL
ADD AX,DX
CALC_END: RET
;---------------
;INPUT: AX=index; OUTPUT: AX=row in record.
CALC_ROW: XOR DX,DX
MOV CX,SIZE INDEX_REC
DIV CX
MOV BL,LINES_PER_REC
XOR BH,BH
INC BX
DIV BX
MOV AX,DX
MUL CX
RET
;----------------------------------------------;
; INPUT: BP=KEYS index; ES=INDEX_SEG or TEMP_RECORD'S CS;
; BX=INDEX offset or TEMP_RECORD'S offset.
; OUTPUT: CF=1 if no word matching WORD_CNT found.
; ELSE: CF=0; BX=word INDEX offset; DI -> word start offset;
; SI -> word end.
WORD_ADDRESS: MOV DH,CS:LINES_PER_REC
INC DH
MOV DL,CS:KEYS.WORD_POS[BP]
OR DL,DL
JS REVERSE
NEXT_LINE: MOV DS,ES:SEG_PTR[BX]
MOV SI,ES:OFF_PTR[BX]
MOV CX,ES:TEXT_LEN[BX]
JCXZ LOOP_LINE
FIND_WORD: LODSB
CMP AL,SPACE
JNZ FIND_WORD_END
LOOP FIND_WORD
JMP SHORT LOOP_LINE
FIND_WORD_END: DEC SI
MOV DI,SI
NEXT_END: LODSB
CMP AL,SPACE
JZ FOUND_END2
LOOP NEXT_END
INC SI ;End of line.
INC CX ;CX off by one
FOUND_END2: DEC DL
JZ FOUND_WORD
DEC CX
JNZ FIND_WORD
JMP SHORT LOOP_LINE
FOUND_WORD: DEC SI
DEC SI
CLC
JMP SHORT ADDRESS_END
LOOP_LINE: ADD BX,SIZE INDEX_REC
DEC DH
JNZ NEXT_LINE
NO_WORD: STC
ADDRESS_END: CLD
RET
;---------------
REVERSE: STD
NEG DL
MOV AH,DH
DEC AH
MOV AL,SIZE INDEX_REC
MUL AH
ADD BX,AX
NEXT_LINE2: MOV DS,ES:SEG_PTR[BX]
MOV SI,ES:OFF_PTR[BX]
MOV CX,ES:TEXT_LEN[BX]
JCXZ LOOP_LINE2
ADD SI,CX
DEC SI
FIND_WORD2: LODSB
CMP AL,SPACE
JNZ WORD_END
LOOP FIND_WORD2
JMP SHORT LOOP_LINE2
WORD_END: INC SI
MOV DI,SI
NEXT_END2: LODSB
CMP AL,SPACE
JZ FOUND_END3
LOOP NEXT_END2
DEC SI ;Start of line.
INC CX ;CX off by one
FOUND_END3: DEC DL
JZ FOUND_WORD2
DEC CX
JNZ FIND_WORD2
JMP SHORT LOOP_LINE2
FOUND_WORD2: INC SI
INC SI
XCHG SI,DI
CLC
JMP ADDRESS_END
LOOP_LINE2: SUB BX,SIZE INDEX_REC
DEC DH
JNZ NEXT_LINE2
JMP NO_WORD
;----------------------------------------------;
UPDATE_TEXT: MOV DH,CURSOR_ROW
INC DH
MOV DL,CURSOR_COLUMN
CALL SET_CURSOR
CALL DISP_DISPLAY
RET
;----------------------------------------------;
; OUTPUT: CF=1 if failed.
LOAD_FILE: CALL ASCIIZ
CALL READ_FILE
JC DISP_ERROR
CALL INDEX
JC DISP_ERROR
CMP LAST_LINE,0
MOV SI,OFFSET FILE_TOO_SMALL
JBE DISP_ERROR
MOV TOP_LINE,0
MOV START_COLUMN,0
MOV MARK_INDEX,-1
MOV CURSOR_ROW,0
MOV CURSOR_COLUMN,0
CLC
JMP SHORT LOAD_END
DISP_ERROR: CALL CLEAR_MENU
CALL WRITE_STRING
MOV SI,OFFSET ESC_MSG
CALL WRITE_STRING
CALL BEEP
STC
LOAD_END: RET
;----------------------------------------------;
; OUTPUT: CF=1 if invalid switch.
PARSE_IT: MOV SI,81H
MOV FILENAME,SI
CALL CAPITALIZE
XOR BP,BP
NEXT_PARSE: CALL PARSE_DELIMIT
LODSB
CMP AL,CR
CLC
JZ PARSE_END
CK_SLASH: CMP AL,"/"
JNZ DO_FILENAME
CALL PARSE_DELIMIT
LODSB
CMP AL,CR
CLC
JZ PARSE_END
CMP AL,"1"
JB CK_SWITCH
CMP AL,"9"
JA CK_SWITCH
DEC SI
CALL SW_BLOCK
JMP NEXT_PARSE
CK_SWITCH: MOV CX,SWITCH_LEN
MOV BX,CX
MOV DI,OFFSET SWITCH_CHARS
MOV DX,DI
ADD DX,CX
REPNZ SCASB
STC
JNZ PARSE_END
SUB BX,CX
DEC BX
SHL BX,1
ADD BX,DX
CALL [BX] ;Process the command.
JMP NEXT_PARSE
DO_FILENAME: DEC SI
MOV FILENAME,SI
FIND_END: LODSB
CMP AL,"/"
JZ FOUND_END
CMP AL,SPACE
JA FIND_END
FOUND_END: DEC SI
JMP NEXT_PARSE
PARSE_END: RET
;-----------------------------------------------------------------;
; INPUT: SI -> string; OUTPUT SI -> first non-white space or CR. ;
;-----------------------------------------------------------------;
PARSE_DELIMIT: PUSH AX
NEXT_DELIMIT: LODSB ;Get a byte.
CMP AL,CR
JZ LEADING_END
CMP AL,SPACE ;Is it a space char or below?
JBE NEXT_DELIMIT
CMP AL,COMMA ;Or comma?
JZ NEXT_DELIMIT
CMP AL,";" ;Or semicolon?
JZ NEXT_DELIMIT ;If yes, parse.
LEADING_END: DEC SI ;Else, adjust pointer to
POP AX
RET ; string start.
;----------------------------------------------;
; INPUT: SI -> string; SI preserved. ;
;----------------------------------------------;
CAPITALIZE: PUSH SI
NEXT_CAP: LODSB
CMP AL,CR
JZ CAP_END
CMP AL,"a"
JB NEXT_CAP
CMP AL,"z"
JA NEXT_CAP
AND BYTE PTR [SI - 1],5FH
JMP NEXT_CAP
CAP_END: POP SI
RET
;----------------------------------------------;
SW_PRIORITY: CALL DECIMAL_INPUT
DEC AX
JS SW_PEND
CMP AX,KEY_MAX - 1
JA SW_PEND
MOV AH,SIZE SORT_KEY
MUL AH
MOV BP,AX
SW_PEND: RET
;----------------------------------------------;
SW_DIRECTION: MOV KEYS.SORT_DIRECTION[BP],DESCEND
RET
;----------------------------------------------;
SW_LINE: MOV KEYS.KEY_FIELD[BP],LINE_TYPE
CALL DECIMAL_INPUT
DEC AX
JS SW_LINE_END
CMP AX,LINES_REC_MAX - 1
JA SW_LINE_END
CMP AL,LINES_PER_REC
JA SW_LINE_END
MOV AH,SIZE INDEX_REC
MUL AH
MOV KEYS.LINE_INDEX[BP],AX
SW_LINE_END: RET
;----------------------------------------------;
SW_BLOCK: MOV KEYS.KEY_FIELD[BP],BLOCK_TYPE
CALL DECIMAL_INPUT
OR AX,AX
JZ STORE_BEG
DEC AX
STORE_BEG: MOV KEYS.BLOCK_BEG[BP],AX
CALL DECIMAL_INPUT
OR AX,AX
JZ SW_BLOCK_END
MOV KEYS.BLOCK_LEN[BP],AX
CALL DECIMAL_INPUT
DEC AX
JS SW_BLOCK_END
MOV AH,SIZE INDEX_REC
MUL AH
MOV KEYS.BLOCK_INDEX[BP],AX
SW_BLOCK_END: RET
;----------------------------------------------;
SW_WORD: MOV KEYS.KEY_FIELD[BP],WORD_TYPE
CALL PARSE_DELIMIT
MOV DI,"+"
CMP BYTE PTR [SI],"+"
JZ GET_SIGN
CMP BYTE PTR [SI],"-"
JNZ GET_WORD_CNT
MOV DI,"-"
GET_SIGN: INC SI
GET_WORD_CNT: CALL DECIMAL_INPUT
CMP AX,1
JB SW_WORD_END
CMP AX,9
JA SW_WORD_END
CMP DI,"+"
JZ STORE_CNT
NEG AL
STORE_CNT: MOV KEYS.WORD_POS[BP],AL
SW_WORD_END: RET
;----------------------------------------------;
SW_RECORDS: CALL DECIMAL_INPUT
DEC AX
JS SW_REND
CMP AX,LINES_REC_MAX - 1
JA SW_REND
MOV LINES_PER_REC,AL
SW_REND: RET
;----------------------------------------------;
SW_NUMERIC: MOV KEYS.KEY_TYPE[BP],NUMERIC_TYPE
RET
;----------------------------------------------;
SW_CASE: MOV CASE,0FFH
RET
;----------------------------------------------;
DECIMAL_INPUT: CALL PARSE_DELIMIT
XOR BX,BX ;Start with zero as number.
NEXT_DECIMAL: LODSB ;Get a character.
SUB AL,"0" ;ASCII to binary.
JC DECIMAL_END ;If not between 0 and 9, skip.
CMP AL,9
JA DECIMAL_END
CBW ;Convert byte to word.
XCHG AX,BX ;Swap old and new number.
MOV CX,10 ;Shift to left by multiplying
MUL CX ; last entry by ten.
ADD BX,AX ;Add new number and store in BX.
JMP NEXT_DECIMAL
DECIMAL_END: DEC SI ;SI -> string end.
MOV AX,BX
RET
;----------------------------------------------;
ASCIIZ: MOV SI,FILENAME
NEXT_ASCIIZ: LODSB
CMP AL,"/"
JZ ASCIIZ_END
CMP AL,SPACE
JA NEXT_ASCIIZ
ASCIIZ_END: MOV BYTE PTR [SI-1],0
RET
;----------------------------------------------;
; OUTPUT: CF=1 if Esc pressed; FILENAME -> filename.
GET_NAME: CALL MENU_OFFSET
ADD DI,CRT_WIDTH
MOV BH,COLOR.B
MOV SI,OFFSET ENTER_FILENAME
CALL WRITE_STRING
MOV SI,FILENAME
MOV FILE_CURSOR,SI
MOV DI,SI
MOV CX,FILENAME_LEN
MOV LINE_START,DI
ADD DI,CX
MOV LINE_END,DI
GET_END: LODSB
CMP AL,"/"
JZ GOT_END3
CMP AL,SPACE
JA GET_END
GOT_END3: DEC SI
MOV CX,LINE_END
SUB CX,SI
MOV AL,SPACE
MOV DI,SI
REP STOSB
XOR AL,AL
STOSB
MOV AL,CR
STOSB
NEXT_FILENAME: CALL MENU_OFFSET
ADD DI,CRT_WIDTH
ADD DI,NAME_CURSOR * 2
MOV BH,COLOR.B
MOV SI,LINE_START
CALL WRITE_STRING
MOV DI,FILE_CURSOR
MOV DX,DI
ADD DL,NAME_CURSOR
SUB DX,LINE_START
MOV DH,ROWS
CALL SET_CURSOR
CALL EDITOR
MOV FILE_CURSOR,DI
JC GET_NAME_END
CMP AH,ENTER_SCAN
JNZ NEXT_FILENAME
GET_NAME_END: RET
;----------------------------------------------;
CK_MODIFIED: CMP MODIFY_FLAG,1
MOV MODIFY_FLAG,0
JNZ MODIFIED_END
CALL HIDE_CURSOR
CALL CLEAR_MENU
MOV BH,COLOR.B
MOV SI,OFFSET SAVE_FILE
CALL WRITE_STRING
CALL CLEAR_KEY
NEXT_MODIFIED: CALL GETKEY
JC MODIFIED_END
AND AH,5FH
CMP AH,"N"
JZ MODIFIED_END
CMP AH,"Y"
JNZ NEXT_MODIFIED
CALL SAVE
MODIFIED_END: RET
;----------------------------------------------;
SAVE: CALL CLEAR_MENU
NEXT_SAVE: CALL GET_NAME
JC SAVE_END
CALL ASCIIZ
MOV DX,FILENAME
MOV AX,3D01H
INT 21H
JC DISP_SAVE_MSG
MOV BX,AX
MOV AX,4400H
INT 21H
MOV AH,3EH
INT 21H
TEST DX,10000000B
STC
JNZ SAVE_FAIL2
DISP_SAVE_MSG: CALL MENU_OFFSET
MOV BH,COLOR.B
MOV SI,OFFSET SAVING
CALL WRITE_STRING
CALL DOS_CURSOR
MOV DX,FILENAME
XOR CX,CX
MOV AH,3CH
INT 21H
JC SAVE_FAIL2
MOV BX,AX
SAVE2: PUSH DS
PUSH ES
MOV BP,LAST_LINE
MOV ES,INDEX_SEG
XOR DI,DI
NEXT_SAVE2: MOV DX,ES:OFF_PTR[DI]
MOV DS,ES:SEG_PTR[DI]
MOV CX,ES:LINE_LEN[DI]
MOV AH,40H
INT 21H
JC SAVE_FAIL
ADD DI,SIZE INDEX_REC
CMP DI,BP
JBE NEXT_SAVE2
MOV AH,3EH
INT 21H
POP ES
POP DS
PUSHF
CALL CLEAR_KEY
POPF
SAVE_END: RET
SAVE_FAIL: POP ES
POP DS
MOV AH,3EH
INT 21H
SAVE_FAIL2: CMP STDIN_FLAG,1
JZ SAVE_END
CALL CLEAR_KEY
CALL MENU_OFFSET
MOV BH,COLOR.B
MOV SI,OFFSET SAVE_FAILED
CALL WRITE_STRING
CALL BEEP
JMP NEXT_SAVE
;----------------------------------------------;
NEW_FILE: CALL CK_MODIFIED
CALL CLEAR_MENU
NEXT_NEW: CALL GET_NAME
JC NEW_END
CALL PARSE_IT
CALL LOAD_FILE
JC NEXT_NEW
NEW_END: RET
;----------------------------------------------;
SORT_INDEX DW ? ;Index row for sort key.
TEMP_RECORD DB LINES_REC_MAX * SIZE INDEX_REC DUP (?)
TEMP_FLAG DB ? ;=1 if temporary swap in progress
SOURCE DW ?
DESTINATION DW ?
SOURCE_INTEGER DB LINE_MAX + 2 DUP (?)
DESTINATION_INTEGER DB LINE_MAX + 2 DUP (?)
SOURCE_DECIMAL DB LINE_MAX + 2 DUP (?)
DESTINATION_DECIMAL DB LINE_MAX + 2 DUP (?)
SORT: CALL HIDE_CURSOR
CALL CLEAR_MENU
PUSH DI
MOV SI,OFFSET SORTING
CALL WRITE_STRING
POP DI
ADD DI,CRT_WIDTH
CALL WRITE_STRING
SORT2: PUSH WORD PTR CURRENT_KEY
MOV CURRENT_KEY,KEY_MAX - 1
NEXT_SORT: CALL GET_PRIORITY
MOV AL,JB_CODE
CMP KEYS.SORT_DIRECTION[BP],ASCEND
JZ GET_KEY_TYPE
MOV AL,JA_CODE
GET_KEY_TYPE: MOV BL,KEYS.KEY_TYPE[BP]
MOV AH,KEYS.KEY_FIELD[BP]
CMP AH,LINE_TYPE
JNZ CK_BLOCK_SORT
CMP BL,ALPHA_TYPE
JZ DO_ALPHA_LINE
CALL SORT_LINE_N
JMP SHORT LOOP_SORT
DO_ALPHA_LINE: CALL SORT_LINE_A
JMP SHORT LOOP_SORT
CK_BLOCK_SORT: CMP AH,BLOCK_TYPE
JNZ CK_WORD_SORT
CMP BL,ALPHA_TYPE
JZ DO_ALPHA_BLK
CALL SORT_BLOCK_N
JMP SHORT LOOP_SORT
DO_ALPHA_BLK: CALL SORT_BLOCK_A
JMP SHORT LOOP_SORT
CK_WORD_SORT: CMP AH,WORD_TYPE
JNZ LOOP_SORT
CMP BL,ALPHA_TYPE
JZ DO_ALPHA_WORD
CALL SORT_WORD_N
JMP SHORT LOOP_SORT
DO_ALPHA_WORD: CALL SORT_WORD_A
LOOP_SORT: DEC CURRENT_KEY
JNS NEXT_SORT
SORT_END: POP WORD PTR CURRENT_KEY
CALL CLEAR_KEY
RET
;----------------------------------------------;
SORT_LINE_A: PUSH DS
PUSH ES
MOV BYTE PTR LINE_JMP,AL
MOV MODIFY_FLAG,1
MOV AX,KEYS.LINE_INDEX[BP]
CALL CALC_ROW
MOV SORT_INDEX,AX
XOR SI,SI ;Source INDEX pointer.
MOV DI,INDEX_PER_REC ;Destination INDEX pointer.
NEXT_SLINE: MOV AX,40H
MOV ES,AX
MOV AX,ES:[1AH]
CMP AX,ES:[1CH]
JZ CK_LINE_DONE
CALL GETKEY
JNC CK_LINE_DONE
JMP SORT_LINE_END
CK_LINE_DONE: MOV AX,DI
ADD AX,INDEX_PER_REC
SUB AX,SIZE INDEX_REC
CMP AX,LAST_LINE
JBE DO_LINE_SORT
JMP SORT_LINE_END
DO_LINE_SORT: PUSH SI
PUSH DI
MOV BX,SI
MOV DX,DI
MOV TEMP_FLAG,0
NEXT_LINE_REC: MOV SI,BX
MOV DI,DX
ADD SI,CS:SORT_INDEX
ADD DI,CS:SORT_INDEX
MOV AX,CS:INDEX_SEG
MOV DS,AX
CMP CS:TEMP_FLAG,1
JNZ GET_LINE_LEN
MOV AX,CS
GET_LINE_LEN: MOV ES,AX
MOV AX,ES:TEXT_LEN[DI]
MOV CX,TEXT_LEN[SI]
MOV CH,AL
MOV AX,ES:OFF_PTR[DI]
MOV ES,ES:SEG_PTR[DI]
MOV DI,AX
MOV AX,OFF_PTR[SI]
MOV DS,SEG_PTR[SI]
MOV SI,AX
JMP SHORT LINE_LENGTH
NEXT_LCOMPARE: DEC CL
DEC CH
LINE_LENGTH: OR CL,CL
JZ CK_LINE_LEN
OR CH,CH
JNZ LINE_BYTE
CK_LINE_LEN: CMP CL,CH
JB LINE_JMP
JZ NO_LINE_SWAP
INC CX
CLC
JMP SHORT LINE_JMP
LINE_BYTE: LODSB
MOV AH,ES:[DI]
INC DI
CMP AL,"a"
JB GET_LDEST
CMP AL,"z"
JA GET_LDEST
AND AL,CS:CASE
GET_LDEST: CMP AH,"a"
JB LCOMPARE
CMP AH,"z"
JA LCOMPARE
AND AH,CS:CASE
LCOMPARE: CMP AL,AH
LINE_JMP: JB NO_LINE_SWAP
JZ NEXT_LCOMPARE
LINE_SWAP: CMP CS:TEMP_FLAG,1
JZ CK_LINE_SWAP
MOV SI,DX
MOV DS,CS:INDEX_SEG
MOV DX,OFFSET TEMP_RECORD
MOV DI,DX
MOV AX,CS
MOV ES,AX
MOV CX,CS:INDEX_PER_REC
REP MOVSB
MOV CS:TEMP_FLAG,1
CK_LINE_SWAP: MOV AX,CS:INDEX_SEG
MOV DS,AX
MOV ES,AX
MOV SI,BX
MOV DI,SI
MOV CX,CS:INDEX_PER_REC
ADD DI,CX
REP MOVSB
SUB BX,CS:INDEX_PER_REC
JS NO_LINE_SWAP
JMP NEXT_LINE_REC
NO_LINE_SWAP: MOV AX,CS
MOV DS,AX
CMP TEMP_FLAG,1
JNZ NO_LINSERT
MOV SI,OFFSET TEMP_RECORD
MOV ES,INDEX_SEG
MOV DI,BX
MOV CX,INDEX_PER_REC
ADD DI,CX
REP MOVSB
NO_LINSERT: POP DI
POP SI
MOV AX,INDEX_PER_REC
ADD SI,AX
ADD DI,AX
JMP NEXT_SLINE
SORT_LINE_END: POP ES
POP DS
RET
;----------------------------------------------;
SORT_BLOCK_A: PUSH DS
PUSH ES
MOV BYTE PTR BLOCK_JMP,AL
CMP KEYS.BLOCK_BEG,INACTIVE
JNZ DO_SORT_BLK
JMP SORT_BLK_END
DO_SORT_BLK: MOV MODIFY_FLAG,1
MOV AX,KEYS.BLOCK_INDEX[BP]
CALL CALC_ROW
MOV SORT_INDEX,AX
XOR SI,SI ;Source INDEX pointer.
MOV DI,INDEX_PER_REC ;Destination INDEX pointer.
NEXT_BLK: MOV AX,40H
MOV ES,AX
MOV AX,ES:[1AH]
CMP AX,ES:[1CH]
JZ CK_BLK_DONE
CALL GETKEY
JNC CK_BLK_DONE
JMP SORT_BLK_END
CK_BLK_DONE: MOV AX,DI
ADD AX,INDEX_PER_REC
SUB AX,SIZE INDEX_REC
CMP AX,LAST_LINE
JBE DO_BLK_SORT
JMP SORT_BLK_END
DO_BLK_SORT: PUSH SI
PUSH DI
MOV BX,SI
MOV DX,DI
MOV TEMP_FLAG,0
NEXT_BLK_REC: MOV SI,BX
MOV DI,DX
ADD SI,CS:SORT_INDEX
ADD DI,CS:SORT_INDEX
MOV AX,CS:INDEX_SEG
MOV DS,AX
CMP CS:TEMP_FLAG,1
JNZ GET_BLK_LEN
MOV AX,CS
GET_BLK_LEN: MOV ES,AX
MOV AX,ES:TEXT_LEN[DI]
MOV CX,TEXT_LEN[SI]
MOV CH,AL
MOV AX,ES:OFF_PTR[DI]
MOV ES,ES:SEG_PTR[DI]
MOV DI,AX
MOV AX,OFF_PTR[SI]
MOV DS,SEG_PTR[SI]
MOV SI,AX
MOV AX,CS:KEYS.BLOCK_BEG[BP]
ADD SI,AX
ADD DI,AX
SUB CL,AL
JNS BLK_LEN2
XOR CL,CL
BLK_LEN2: SUB CH,AL
JNS BLK_LEN3
XOR CH,CH
BLK_LEN3: MOV AX,CS:KEYS.BLOCK_LEN[BP]
CMP CL,AL
JB BLK_LEN4
MOV CL,AL
BLK_LEN4: CMP CH,AL
JB BLK_LENGTH
MOV CH,AL
JMP SHORT BLK_LENGTH
NEXT_BCOMPARE: DEC CL
DEC CH
BLK_LENGTH: OR CL,CL
JZ CK_BLK_LEN
OR CH,CH
JNZ BLK_BYTE
CK_BLK_LEN: CMP CL,CH
JB BLOCK_JMP
JZ NO_BLK_SWAP
INC CX
CLC
JMP SHORT BLOCK_JMP
BLK_BYTE: LODSB
MOV AH,ES:[DI]
INC DI
CMP AL,"a"
JB GET_BDEST
CMP AL,"z"
JA GET_BDEST
AND AL,CS:CASE
GET_BDEST: CMP AH,"a"
JB BCOMPARE
CMP AH,"z"
JA BCOMPARE
AND AH,CS:CASE
BCOMPARE: CMP AL,AH
BLOCK_JMP: JB NO_BLK_SWAP
JZ NEXT_BCOMPARE
BLK_SWAP: CMP CS:TEMP_FLAG,1
JZ CK_BLK_SWAP
MOV SI,DX
MOV DS,CS:INDEX_SEG
MOV DX,OFFSET TEMP_RECORD
MOV DI,DX
MOV AX,CS
MOV ES,AX
MOV CX,CS:INDEX_PER_REC
REP MOVSB
MOV CS:TEMP_FLAG,1
CK_BLK_SWAP: MOV AX,CS:INDEX_SEG
MOV DS,AX
MOV ES,AX
MOV SI,BX
MOV DI,SI
MOV CX,CS:INDEX_PER_REC
ADD DI,CX
REP MOVSB
SUB BX,CS:INDEX_PER_REC
JS NO_BLK_SWAP
JMP NEXT_BLK_REC
NO_BLK_SWAP: MOV AX,CS
MOV DS,AX
CMP TEMP_FLAG,1
JNZ NO_BINSERT
MOV SI,OFFSET TEMP_RECORD
MOV ES,INDEX_SEG
MOV DI,BX
MOV CX,INDEX_PER_REC
ADD DI,CX
REP MOVSB
NO_BINSERT: POP DI
POP SI
MOV AX,INDEX_PER_REC
ADD SI,AX
ADD DI,AX
JMP NEXT_BLK
SORT_BLK_END: POP ES
POP DS
RET
;----------------------------------------------;
SORT_WORD_A: PUSH DS
PUSH ES
MOV BYTE PTR WORD_JMP,AL
MOV MODIFY_FLAG,1
XOR SI,SI
MOV DI,INDEX_PER_REC
NEXT_WLINE: MOV AX,40H
MOV ES,AX
MOV AX,ES:[1AH]
CMP AX,ES:[1CH]
JZ CK_WORD_DONE
CALL GETKEY
JNC CK_WORD_DONE
JMP SORT_WORD_END
CK_WORD_DONE: MOV AX,DI
ADD AX,INDEX_PER_REC
SUB AX,SIZE INDEX_REC
CMP AX,LAST_LINE
JBE DO_WORD_SORT
JMP SORT_WORD_END
DO_WORD_SORT: PUSH SI
PUSH DI
MOV SOURCE,SI
MOV DESTINATION,DI
MOV TEMP_FLAG,0
NEXT_WORD_REC: MOV ES,CS:INDEX_SEG
MOV BX,CS:SOURCE
CALL WORD_ADDRESS
MOV AX,DS
PUSH AX
JC STORE_SLEN
MOV CX,SI
SUB CX,DI
INC CX
STORE_SLEN: PUSH CX
PUSH DI
CMP CS:TEMP_FLAG,1
JNZ GET_DEST_WORD
MOV AX,CS
MOV ES,AX
GET_DEST_WORD: MOV BX,CS:DESTINATION
CALL WORD_ADDRESS
MOV AX,DS
MOV ES,AX
JC GOT_DEST_WORD
MOV CX,SI
SUB CX,DI
INC CX
GOT_DEST_WORD: MOV CH,CL
POP SI
POP AX
MOV CL,AL
POP DS
JMP SHORT WORD_LENGTH
NEXT_WCOMPARE: DEC CL
DEC CH
WORD_LENGTH: OR CL,CL
JZ CK_WORD_LEN
OR CH,CH
JNZ WORD_BYTE
CK_WORD_LEN: CMP CL,CH
JB WORD_JMP
JZ NO_WORD_SWAP
INC CX
CLC
JMP SHORT WORD_JMP
WORD_BYTE: LODSB
MOV AH,ES:[DI]
INC DI
CMP AL,"a"
JB GET_WDEST
CMP AL,"z"
JA GET_WDEST
AND AL,CS:CASE
GET_WDEST: CMP AH,"a"
JB WCOMPARE
CMP AH,"z"
JA WCOMPARE
AND AH,CS:CASE
WCOMPARE: CMP AL,AH
WORD_JMP: JB NO_WORD_SWAP
JZ NEXT_WCOMPARE
WORD_SWAP: CMP CS:TEMP_FLAG,1
JZ CK_WORD_SWAP
MOV SI,CS:DESTINATION
MOV DS,CS:INDEX_SEG
MOV DI,OFFSET TEMP_RECORD
MOV CS:DESTINATION,DI
MOV AX,CS
MOV ES,AX
MOV CX,CS:INDEX_PER_REC
REP MOVSB
MOV CS:TEMP_FLAG,1
CK_WORD_SWAP: MOV AX,CS:INDEX_SEG
MOV DS,AX
MOV ES,AX
MOV SI,CS:SOURCE
MOV DI,SI
MOV CX,CS:INDEX_PER_REC
MOV AX,CX
ADD DI,CX
REP MOVSB
SUB CS:SOURCE,AX
JS NO_WORD_SWAP
JMP NEXT_WORD_REC
NO_WORD_SWAP: MOV AX,CS
MOV DS,AX
CMP TEMP_FLAG,1
JNZ NO_WINSERT
MOV SI,OFFSET TEMP_RECORD
MOV ES,INDEX_SEG
MOV DI,SOURCE
MOV CX,INDEX_PER_REC
ADD DI,CX
REP MOVSB
NO_WINSERT: POP DI
POP SI
MOV AX,INDEX_PER_REC
ADD SI,AX
ADD DI,AX
JMP NEXT_WLINE
SORT_WORD_END: POP ES
POP DS
RET
;----------------------------------------------;
SORT_LINE_N: PUSH DS
PUSH ES
MOV BYTE PTR LINE_JMPN1,AL
MOV BYTE PTR LINE_JMPN2,AL
MOV BYTE PTR LINE_JMPN3,AL
MOV MODIFY_FLAG,1
MOV AX,KEYS.LINE_INDEX[BP]
CALL CALC_ROW
MOV SORT_INDEX,AX
XOR SI,SI ;Source INDEX pointer.
MOV DI,INDEX_PER_REC ;Destination INDEX pointer.
NEXT_SLINEN: MOV AX,40H
MOV ES,AX
MOV AX,ES:[1AH]
CMP AX,ES:[1CH]
JZ CK_LINE_DONEN
CALL GETKEY
JNC CK_LINE_DONEN
JMP SORT_LINE_ENDN
CK_LINE_DONEN: MOV AX,DI
ADD AX,INDEX_PER_REC
SUB AX,SIZE INDEX_REC
CMP AX,LAST_LINE
JBE DO_LINE_SORTN
JMP SORT_LINE_ENDN
DO_LINE_SORTN: PUSH SI
PUSH DI
MOV SOURCE,SI
MOV DESTINATION,DI
MOV TEMP_FLAG,0
NEXT_LINE_RECN:MOV DI,CS:SOURCE
ADD DI,CS:SORT_INDEX
MOV DS,CS:INDEX_SEG
MOV CX,TEXT_LEN[DI]
MOV SI,OFF_PTR[DI]
MOV DS,SEG_PTR[DI]
MOV AX,CS
MOV ES,AX
MOV DI,OFFSET SOURCE_INTEGER
CALL GET_INTEGER
MOV BX,DX
MOV DI,OFFSET SOURCE_DECIMAL
CALL GET_DECIMAL
MOV DI,CS:DESTINATION
ADD DI,CS:SORT_INDEX
MOV AX,CS:INDEX_SEG
CMP CS:TEMP_FLAG,1
JNZ GOT_LINE_SEG
MOV AX,CS
GOT_LINE_SEG: MOV DS,AX
MOV CX,TEXT_LEN[DI]
MOV SI,OFF_PTR[DI]
MOV DS,SEG_PTR[DI]
MOV DI,OFFSET DESTINATION_INTEGER
CALL GET_INTEGER
MOV DI,OFFSET DESTINATION_DECIMAL
CALL GET_DECIMAL
MOV AX,CS
MOV DS,AX
MOV SI,OFFSET SOURCE_INTEGER
MOV DI,OFFSET DESTINATION_INTEGER
CMPSB
JNZ LINE_JMPN1
XOR AL,AL
CMP BYTE PTR [SI-1],PLUS_SIGN
JZ LINE_SIZE
INC AL
XCHG BX,DX
XCHG SI,DI
LINE_SIZE: CMP BX,DX
LINE_JMPN1: JB NO_LINE_SWAPN
JZ LINE_INTEGER
JMP SHORT LINE_SWAPN
LINE_INTEGER: OR DX,DX
JZ LINE_DECIMAL
NEXT_INT_CMP: CMPSB
LINE_JMPN2: JB NO_LINE_SWAPN
JZ LOOP_INT
JMP SHORT LINE_SWAPN
LOOP_INT: DEC DX
JNZ NEXT_INT_CMP
LINE_DECIMAL: MOV SI,OFFSET SOURCE_DECIMAL
MOV DI,OFFSET DESTINATION_DECIMAL
OR AL,AL
JZ NEXT_DEC_CMP
XCHG SI,DI
NEXT_DEC_CMP: LODSB
SCASB
LINE_JMPN3: JB NO_LINE_SWAPN
JZ CK_LINE_NULL
JMP SHORT LINE_SWAPN
CK_LINE_NULL: OR AL,AL
JNZ NEXT_DEC_CMP
JMP SHORT NO_LINE_SWAPN
LINE_SWAPN: CMP TEMP_FLAG,1
JZ CK_LINE_SWAPN
MOV TEMP_FLAG,1
MOV SI,DESTINATION
MOV DI,OFFSET TEMP_RECORD
MOV DESTINATION,DI
MOV CX,INDEX_PER_REC
MOV DS,INDEX_SEG
MOV AX,CS
MOV ES,AX
REP MOVSB
CK_LINE_SWAPN: MOV AX,CS:INDEX_SEG
MOV DS,AX
MOV ES,AX
MOV SI,CS:SOURCE
MOV DI,SI
MOV CX,CS:INDEX_PER_REC
MOV AX,CX
ADD DI,CX
REP MOVSB
SUB CS:SOURCE,AX
JS NO_LINE_SWAPN
JMP NEXT_LINE_RECN
NO_LINE_SWAPN: MOV AX,CS
MOV DS,AX
CMP TEMP_FLAG,1
JNZ NO_LINSERTN
MOV SI,OFFSET TEMP_RECORD
MOV ES,INDEX_SEG
MOV DI,SOURCE
MOV CX,INDEX_PER_REC
ADD DI,CX
REP MOVSB
NO_LINSERTN: POP DI
POP SI
MOV AX,INDEX_PER_REC
ADD SI,AX
ADD DI,AX
JMP NEXT_SLINEN
SORT_LINE_ENDN:POP ES
POP DS
RET
;----------------------------------------------;
SORT_BLOCK_N: PUSH DS
PUSH ES
MOV BYTE PTR BLOCK_JMPN1,AL
MOV BYTE PTR BLOCK_JMPN2,AL
MOV BYTE PTR BLOCK_JMPN3,AL
CMP KEYS.BLOCK_BEG,INACTIVE
JNZ DO_SORT_BLKN
JMP SORT_BLK_ENDN
DO_SORT_BLKN: MOV MODIFY_FLAG,1
MOV AX,KEYS.BLOCK_INDEX[BP]
CALL CALC_ROW
MOV SORT_INDEX,AX
XOR SI,SI ;Source INDEX pointer.
MOV DI,INDEX_PER_REC ;Destination INDEX pointer.
NEXT_BLKN: MOV AX,40H
MOV ES,AX
MOV AX,ES:[1AH]
CMP AX,ES:[1CH]
JZ CK_BLK_DONEN
CALL GETKEY
JNC CK_BLK_DONEN
JMP SORT_BLK_ENDN
CK_BLK_DONEN: MOV AX,DI
ADD AX,INDEX_PER_REC
SUB AX,SIZE INDEX_REC
CMP AX,LAST_LINE
JBE DO_BLK_SORTN
JMP SORT_BLK_ENDN
DO_BLK_SORTN: PUSH SI
PUSH DI
MOV SOURCE,SI
MOV DESTINATION,DI
MOV TEMP_FLAG,0
NEXT_BLK_RECN: MOV DI,CS:SOURCE
ADD DI,CS:SORT_INDEX
MOV DS,CS:INDEX_SEG
MOV CX,TEXT_LEN[DI]
MOV SI,OFF_PTR[DI]
MOV DS,SEG_PTR[DI]
MOV AX,CS:KEYS.BLOCK_BEG[BP]
ADD SI,AX
SUB CX,AX
JNS BLK_SOURCE1
XOR CX,CX
BLK_SOURCE1: MOV AX,CS:KEYS.BLOCK_LEN[BP]
CMP CX,AX
JB BLK_SOURCE2
MOV CX,AX
BLK_SOURCE2: MOV AX,CS
MOV ES,AX
MOV DI,OFFSET SOURCE_INTEGER
CALL GET_INTEGER
MOV BX,DX
MOV DI,OFFSET SOURCE_DECIMAL
CALL GET_DECIMAL
MOV DI,CS:DESTINATION
ADD DI,CS:SORT_INDEX
MOV AX,CS:INDEX_SEG
CMP CS:TEMP_FLAG,1
JNZ GOT_BLK_SEG
MOV AX,CS
GOT_BLK_SEG: MOV DS,AX
MOV CX,TEXT_LEN[DI]
MOV SI,OFF_PTR[DI]
MOV DS,SEG_PTR[DI]
MOV AX,CS:KEYS.BLOCK_BEG[BP]
ADD SI,AX
SUB CX,AX
JNS BLK_DEST1
XOR CX,CX
BLK_DEST1: MOV AX,CS:KEYS.BLOCK_LEN[BP]
CMP CX,AX
JB BLK_DEST2
MOV CX,AX
BLK_DEST2: MOV DI,OFFSET DESTINATION_INTEGER
CALL GET_INTEGER
MOV DI,OFFSET DESTINATION_DECIMAL
CALL GET_DECIMAL
MOV AX,CS
MOV DS,AX
MOV SI,OFFSET SOURCE_INTEGER
MOV DI,OFFSET DESTINATION_INTEGER
CMPSB
JNZ BLOCK_JMPN1
XOR AL,AL
CMP BYTE PTR [SI-1],PLUS_SIGN
JZ BLOCK_SIZE
INC AL
XCHG BX,DX
XCHG SI,DI
BLOCK_SIZE: CMP BX,DX
BLOCK_JMPN1: JB NO_BLK_SWAPN
JZ BLK_INTEGER
JMP SHORT BLK_SWAPN
BLK_INTEGER: OR DX,DX
JZ BLK_DECIMAL
NEXT_BLK_CMP: CMPSB
BLOCK_JMPN2: JB NO_BLK_SWAPN
JZ LOOP_BLK
JMP SHORT BLK_SWAPN
LOOP_BLK: DEC DX
JNZ NEXT_BLK_CMP
BLK_DECIMAL: MOV SI,OFFSET SOURCE_DECIMAL
MOV DI,OFFSET DESTINATION_DECIMAL
OR AL,AL
JZ NEXT_BLK_CMP2
XCHG SI,DI
NEXT_BLK_CMP2: LODSB
SCASB
BLOCK_JMPN3: JB NO_BLK_SWAPN
JZ CK_BLK_NULL
JMP SHORT BLK_SWAPN
CK_BLK_NULL: OR AL,AL
JNZ NEXT_BLK_CMP2
JMP SHORT NO_BLK_SWAPN
BLK_SWAPN: CMP TEMP_FLAG,1
JZ CK_BLK_SWAPN
MOV TEMP_FLAG,1
MOV SI,DESTINATION
MOV DI,OFFSET TEMP_RECORD
MOV DESTINATION,DI
MOV CX,INDEX_PER_REC
MOV DS,INDEX_SEG
MOV AX,CS
MOV ES,AX
REP MOVSB
CK_BLK_SWAPN: MOV AX,CS:INDEX_SEG
MOV DS,AX
MOV ES,AX
MOV SI,CS:SOURCE
MOV DI,SI
MOV CX,CS:INDEX_PER_REC
MOV AX,CX
ADD DI,CX
REP MOVSB
SUB CS:SOURCE,AX
JS NO_BLK_SWAPN
JMP NEXT_BLK_RECN
NO_BLK_SWAPN: MOV AX,CS
MOV DS,AX
CMP TEMP_FLAG,1
JNZ NO_BINSERTN
MOV SI,OFFSET TEMP_RECORD
MOV ES,INDEX_SEG
MOV DI,SOURCE
MOV CX,INDEX_PER_REC
ADD DI,CX
REP MOVSB
NO_BINSERTN: POP DI
POP SI
MOV AX,INDEX_PER_REC
ADD SI,AX
ADD DI,AX
JMP NEXT_BLKN
SORT_BLK_ENDN: POP ES
POP DS
RET
;----------------------------------------------;
SORT_WORD_N: PUSH DS
PUSH ES
MOV BYTE PTR WORD_JMPN1,AL
MOV BYTE PTR WORD_JMPN2,AL
MOV BYTE PTR WORD_JMPN3,AL
MOV MODIFY_FLAG,1
XOR SI,SI
MOV DI,INDEX_PER_REC
NEXT_WLINEN: MOV AX,40H
MOV ES,AX
MOV AX,ES:[1AH]
CMP AX,ES:[1CH]
JZ CK_WORD_DONEN
CALL GETKEY
JNC CK_WORD_DONEN
JMP SORT_WORD_ENDN
CK_WORD_DONEN: MOV AX,DI
ADD AX,INDEX_PER_REC
SUB AX,SIZE INDEX_REC
CMP AX,LAST_LINE
JBE DO_WORD_SORTN
JMP SORT_WORD_ENDN
DO_WORD_SORTN: PUSH SI
PUSH DI
MOV SOURCE,SI
MOV DESTINATION,DI
MOV TEMP_FLAG,0
NEXT_WORD_RECN:MOV ES,CS:INDEX_SEG
MOV BX,CS:SOURCE
CALL WORD_ADDRESS
JC WORD_SOURCE
MOV CX,SI
SUB CX,DI
INC CX
WORD_SOURCE: MOV SI,DI
MOV AX,CS
MOV ES,AX
MOV DI,OFFSET SOURCE_INTEGER
CALL GET_INTEGER
PUSH DX
MOV DI,OFFSET SOURCE_DECIMAL
CALL GET_DECIMAL
MOV AX,CS:INDEX_SEG
CMP CS:TEMP_FLAG,1
JNZ GET_DEST_WORDN
MOV AX,CS
GET_DEST_WORDN:MOV ES,AX
MOV BX,CS:DESTINATION
CALL WORD_ADDRESS
JC WORD_DEST
MOV CX,SI
SUB CX,DI
INC CX
WORD_DEST: MOV SI,DI
MOV AX,CS
MOV ES,AX
MOV DI,OFFSET DESTINATION_INTEGER
CALL GET_INTEGER
MOV DI,OFFSET DESTINATION_DECIMAL
CALL GET_DECIMAL
MOV AX,CS
MOV DS,AX
POP BX
MOV SI,OFFSET SOURCE_INTEGER
MOV DI,OFFSET DESTINATION_INTEGER
CMPSB
JNZ WORD_JMPN1
XOR AL,AL
CMP BYTE PTR [SI-1],PLUS_SIGN
JZ WORD_SIZE
INC AL
XCHG BX,DX
XCHG SI,DI
WORD_SIZE: CMP BX,DX
WORD_JMPN1: JB NO_WORD_SWAPN
JZ WORD_INTEGER
JMP SHORT WORD_SWAPN
WORD_INTEGER: OR DX,DX
JZ WORD_DECIMAL
NEXT_WORD_CMP: CMPSB
WORD_JMPN2: JB NO_WORD_SWAPN
JZ LOOP_WORD
JMP SHORT WORD_SWAPN
LOOP_WORD: DEC DX
JNZ NEXT_WORD_CMP
WORD_DECIMAL: MOV SI,OFFSET SOURCE_DECIMAL
MOV DI,OFFSET DESTINATION_DECIMAL
OR AL,AL
JZ NEXT_WORD_CMP2
XCHG SI,DI
NEXT_WORD_CMP2:LODSB
SCASB
WORD_JMPN3: JB NO_WORD_SWAPN
JZ CK_WORD_NULL
JMP SHORT WORD_SWAPN
CK_WORD_NULL: OR AL,AL
JNZ NEXT_WORD_CMP2
JMP SHORT NO_WORD_SWAPN
WORD_SWAPN: CMP TEMP_FLAG,1
JZ CK_WORD_SWAPN
MOV TEMP_FLAG,1
MOV SI,DESTINATION
MOV DI,OFFSET TEMP_RECORD
MOV DESTINATION,DI
MOV CX,INDEX_PER_REC
MOV DS,INDEX_SEG
MOV AX,CS
MOV ES,AX
REP MOVSB
CK_WORD_SWAPN: MOV AX,CS:INDEX_SEG
MOV DS,AX
MOV ES,AX
MOV SI,CS:SOURCE
MOV DI,SI
MOV CX,CS:INDEX_PER_REC
MOV AX,CX
ADD DI,CX
REP MOVSB
SUB CS:SOURCE,AX
JS NO_WORD_SWAPN
JMP NEXT_WORD_RECN
NO_WORD_SWAPN: MOV AX,CS
MOV DS,AX
CMP TEMP_FLAG,1
JNZ NO_WINSERTN
MOV SI,OFFSET TEMP_RECORD
MOV ES,INDEX_SEG
MOV DI,SOURCE
MOV CX,INDEX_PER_REC
ADD DI,CX
REP MOVSB
NO_WINSERTN: POP DI
POP SI
MOV AX,INDEX_PER_REC
ADD SI,AX
ADD DI,AX
JMP NEXT_WLINEN
SORT_WORD_ENDN:POP ES
POP DS
RET
;----------------------------------------------;
; INPUT: DS:SI -> string; ES:DI-> Storage; CX=text length;
; OUTPUT: DX=integer length.
GET_INTEGER: XOR DX,DX
MOV AH,MINUS_SIGN
MOV AL,PLUS_SIGN
STOSB
JCXZ INTEGER_END
NEXT_INTEGER: LODSB
CMP AL,DECIMAL_POINT
JZ INTEGER_DONE
CMP AL,AH
JZ STORE_NEGATIVE
CMP AL,"0"
JB LOOP_INTEGER
CMP AL,"9"
JA LOOP_INTEGER
STOSB
XOR AH,AH
INC DX
LOOP_INTEGER: LOOP NEXT_INTEGER
INC CX
INTEGER_DONE: DEC CX
INTEGER_END: RET
STORE_NEGATIVE:XOR AH,AH
MOV BYTE PTR ES:[DI-1],AH
JMP LOOP_INTEGER
;----------------------------------------------;
; INPUT: DI-> Storage; CX=text length; OUTPUT: NULL terminated.
GET_DECIMAL: JCXZ DEC_END
NEXT_DEC: LODSB
CMP AL,"0"
JB DEC_DONE
CMP AL,"9"
JA DEC_DONE
STOSB
LOOP NEXT_DEC
INC CX
DEC_DONE: DEC CX
DEC_END: XOR AL,AL
STOSB
RET
;----------------------------------------------;
SH_LINE_REC: MOV AL,-1
JMP SHORT DO_LINES_REC
LINES_REC: MOV AL,1
DO_LINES_REC: MOV BL,LINES_PER_REC
ADD BL,AL
JNS CK_LINES_REC
MOV BL,LINES_REC_MAX - 1
CK_LINES_REC: CMP BL,LINES_REC_MAX
JB LINES_REC_END
XOR BL,BL
LINES_REC_END: MOV LINES_PER_REC,BL
INC BL
MOV AL,SIZE INDEX_REC
MUL BL
MOV INDEX_PER_REC,AX
RET
;----------------------------------------------;
SH_PRIORITY: MOV AL,-1
JMP SHORT DO_PRIORITY
PRIORITY: MOV AL,1
DO_PRIORITY: MOV BL,CURRENT_KEY
ADD BL,AL
JNS CK_PRIORITY
MOV BL,KEY_MAX - 1
CK_PRIORITY: CMP BL,KEY_MAX
JB PRIORITY_END
XOR BL,BL
PRIORITY_END: MOV CURRENT_KEY,BL
RET
;----------------------------------------------;
DIRECTION: CALL GET_PRIORITY
XOR KEYS.SORT_DIRECTION[BP],1
RET
;----------------------------------------------;
SORT_TYPE: CALL GET_PRIORITY
XOR KEYS.KEY_TYPE[BP],1
RET
;----------------------------------------------;
SH_FIELD_TYPE: MOV AL,-1
JMP SHORT DO_FIELD
FIELD_TYPE: MOV AL,1
DO_FIELD: CALL GET_PRIORITY
MOV BL,KEYS.KEY_FIELD[BP]
ADD BL,AL
JNS CK_FIELD
MOV BL,LINE_TYPE
CK_FIELD: CMP BL,LINE_TYPE
JBE FIELD_END
XOR BL,BL
FIELD_END: MOV KEYS.KEY_FIELD[BP],BL
RET
;----------------------------------------------;
SH_BLOCKSTART: MOV AL,-1
JMP SHORT DO_BLOCKSTART
BLOCKSTART: MOV AL,1
DO_BLOCKSTART: CALL GET_PRIORITY
MOV BL,KEYS.KEY_FIELD[BP]
CMP BL,BLOCK_TYPE
JNZ CK_LINE
CALL MARK_BLOCK
JMP SHORT BLOCKEND
CK_LINE: CMP BL,LINE_TYPE
JNZ CK_WORD
MOV AL,CURSOR_ROW
XOR AH,AH
MOV CL,SIZE INDEX_REC
MUL CL
ADD AX,TOP_LINE
MOV KEYS.LINE_INDEX[BP],AX
JMP SHORT BLOCKEND
CK_WORD: CMP BL,WORD_TYPE
JNZ BLOCKEND
MOV BL,KEYS.WORD_POS[BP]
SKIP_ZERO: ADD BL,AL
OR BL,BL
JZ SKIP_ZERO
CMP BL,9
JLE CK_LOW
MOV BL,-9
CK_LOW: CMP BL,-9
JGE STORE_WORD
MOV BL,9
STORE_WORD: MOV KEYS.WORD_POS[BP],BL
BLOCKEND: RET
;---------------
LAST_COLUMN DW ?
MARK_BLOCK: CALL MENU_OFFSET
ADD DI,CRT_WIDTH
ADD DI,2 * 56
MOV SI,OFFSET END_MSG
MOV BH,COLOR.B
CALL WRITE_STRING
MOV AL,SIZE INDEX_REC
MUL CURSOR_ROW
ADD AX,TOP_LINE
MOV MARK_INDEX,AX
MOV AL,CURSOR_COLUMN
XOR AH,AH
ADD AX,START_COLUMN
MOV MARK_LEFT,AX
MOV MARK_RIGHT,AX
MOV LAST_COLUMN,AX
NEXT_MARK: MOV AL,CURSOR_COLUMN
XOR AH,AH
MOV BX,LAST_COLUMN
MOV LAST_COLUMN,AX
CMP AX,MARK_LEFT
JB STORE_LEFT
CMP AX,MARK_RIGHT
JA STORE_RIGHT
CMP AX,BX
JA STORE_LEFT
STORE_RIGHT: MOV MARK_RIGHT,AX
JMP SHORT UPDATE_IT
STORE_LEFT: MOV MARK_LEFT,AX
UPDATE_IT: CALL UPDATE_TEXT
CALL CLEAR_KEY
CALL GETKEY
JC MARKBLOCK_END
CMP AL,LEFT_SCAN
JNZ CK_MARK_RIGHT
CALL LEFT
JMP NEXT_MARK
CK_MARK_RIGHT: CMP AL,RIGHT_SCAN
JNZ CK_F10
CALL RIGHT
JMP NEXT_MARK
CK_F10: CMP AL,F10_SCAN
JZ GOT_MARK
CMP AH,CR
JNZ NEXT_MARK
GOT_MARK: MOV AX,MARK_INDEX
MOV KEYS.BLOCK_INDEX[BP],AX
MOV AX,MARK_LEFT
MOV KEYS.BLOCK_BEG[BP],AX
MOV BX,MARK_RIGHT
SUB BX,AX
INC BX
MOV KEYS.BLOCK_LEN[BP],BX
MARKBLOCK_END: RET
;----------------------------------------------;
RESET: MOV CURRENT_KEY,KEY_MAX - 1
NEXT_RESET: CALL GET_PRIORITY
MOV KEYS.SORT_DIRECTION[BP],ASCEND
MOV KEYS.KEY_TYPE[BP],ALPHA_TYPE
MOV KEYS.KEY_FIELD[BP],NONE_TYPE
MOV KEYS.BLOCK_INDEX[BP],0
MOV KEYS.BLOCK_BEG[BP],INACTIVE
MOV KEYS.WORD_POS[BP],1
MOV KEYS.LINE_INDEX[BP],0
DEC CURRENT_KEY
JNS NEXT_RESET
MOV LINES_PER_REC,0
MOV INDEX_PER_REC,SIZE INDEX_REC
MOV CURRENT_KEY,0
RET
;----------------------------------------------;
HELP_ROW EQU 6
HELP_COL EQU 2 * 8
HELP_WIDTH EQU 62
HELP_HEADING LABEL BYTE
DB "║ Priority Field Field ID Direction Type ║",0
HELP_MSG LABEL BYTE
DB "║ Press Alt F1 to reset. Any other key to continue. ║",0
HELP: CALL HIDE_CURSOR
MOV AX,HELP_ROW
CALL CALC_ADDR
ADD DI,HELP_COL
MOV BH,COLOR.B
PUSH DI
MOV AL,"╔"
CALL WRITE_SCREEN
MOV AL,"═"
MOV CX,HELP_WIDTH - 2
CALL REPEAT_CHAR
MOV AL,"╗"
CALL WRITE_SCREEN
POP DI
ADD DI,CRT_WIDTH
PUSH DI
MOV SI,OFFSET HELP_HEADING
CALL WRITE_STRING
POP DI
ADD DI,CRT_WIDTH
MOV BP,KEY_MAX
NEXT_HELP: PUSH DI
MOV AL,"║"
CALL WRITE_SCREEN
MOV AL,SPACE
MOV CX,HELP_WIDTH - 2
CALL REPEAT_CHAR
MOV AL,"║"
CALL WRITE_SCREEN
POP DI
ADD DI,CRT_WIDTH
DEC BP
JNZ NEXT_HELP
PUSH DI
MOV SI,OFFSET HELP_MSG
CALL WRITE_STRING
POP DI
ADD DI,CRT_WIDTH
MOV AL,"╚"
CALL WRITE_SCREEN
MOV AL,"═"
MOV CX,HELP_WIDTH - 2
CALL REPEAT_CHAR
MOV AL,"╝"
CALL WRITE_SCREEN
;--------------------
MOV AX,HELP_ROW + 2
CALL CALC_ADDR
ADD DI,HELP_COL + (2 * 5)
PUSH WORD PTR CURRENT_KEY
MOV CURRENT_KEY,0
NEXT_HELP2: PUSH DI
MOV AL,CURRENT_KEY
ADD AL,"1"
CALL WRITE_SCREEN
CALL GET_PRIORITY
ADD DI,2 * 7
CALL DISP_TYPE
CMP CL,NONE_TYPE
JZ LOOP_HELP
ADD DI,2 * 3
PUSH DI
CMP CL,LINE_TYPE
JNZ CK_HELP_BLK
CALL DISP_LINE
JMP SHORT HELP_TYPE_DONE
CK_HELP_BLK: CMP CL,BLOCK_TYPE
JNZ DO_HELP_WORD
CALL DISP_BLOCK
JMP SHORT HELP_TYPE_DONE
DO_HELP_WORD: CALL DISP_WORD
HELP_TYPE_DONE:POP DI
ADD DI,2 * 13
PUSH DI
ADD DI,2
CALL DISP_ASCEND
POP DI
ADD DI,2 * 14
CALL DISP_ALPHA
LOOP_HELP: POP DI
ADD DI,CRT_WIDTH
INC CURRENT_KEY
CMP CURRENT_KEY,KEY_MAX
JB NEXT_HELP2
POP WORD PTR CURRENT_KEY
;--------------------
CALL GETKEY
CMP AL,ALT_F1
JNZ HELP_END
CALL RESET
CALL DISPLAY_MENU
JMP HELP
HELP_END: RET
;----------------------------------------------;
; INPUT: DI=TOP_LINE, SI=Bottom offset, DX=Bottom cursor line; CX=SIZE INDEX_REC
UP: MOV AL,-1
NEG CX
JMP SHORT DO_UP_DN
DOWN: MOV AL,1
DO_UP_DN: MOV AH,CURSOR_ROW
ADD AH,AL
JS CK_PAGE
CMP AH,DL
JA CK_PAGE
MOV CURSOR_ROW,AH
JMP SHORT UP_DN_END
CK_PAGE: ADD DI,CX
JS UP_DN_END
ADD SI,CX
CMP SI,LAST_LINE
JA UP_DN_END
MOV TOP_LINE,DI
UP_DN_END: RET
;---------------;
PGUP: NEG CX
PGDN: MOV BP,DX
MOV AX,LISTING_LEN
MUL CX
ADD DI,AX
JS HOME_PAGE
ADD SI,AX
CMP SI,LAST_LINE
JBE PAGE_END
MOV DX,BP
MOV CURSOR_ROW,DL
MOV DI,LAST_LINE
ADD DI,SIZE INDEX_REC
SUB DI,AX
JNS PAGE_END
XOR DI,DI
JMP SHORT PAGE_END
HOME_PAGE: XOR DI,DI
MOV CURSOR_ROW,0
PAGE_END: MOV TOP_LINE,DI
RET
;---------------;
LEFT: MOV AX,-1
JMP SHORT DO_LEFT_RIGHT
RIGHT: MOV AX,1
DO_LEFT_RIGHT: MOV BX,START_COLUMN
MOV DL,CURSOR_COLUMN
MOV CX,COLUMNS
ADD DL,AL
JS CK_COL
CMP DL,CL
JAE CK_COL
MOV CURSOR_COLUMN,DL
JMP SHORT LFT_RGT_END
CK_COL: ADD BX,AX
JS LFT_RGT_END
ADD CX,BX
CMP CX,LONGEST_LINE
JA LFT_RGT_END
MOV START_COLUMN,BX
LFT_RGT_END: RET
;---------------;
HOME_KEY: CMP CURSOR_COLUMN,0
MOV CURSOR_COLUMN,0
MOV START_COLUMN,0
JNZ HOME_END
CMP CURSOR_ROW,0
MOV CURSOR_ROW,0
JNZ HOME_END
MOV TOP_LINE,0
HOME_END: RET
END_KEY: MOV AX,LONGEST_LINE
DEC AX
MOV BX,COLUMNS
DEC BX
SUB AX,BX
JNS GOT_END
XOR AX,AX
GOT_END: CMP START_COLUMN,AX
MOV START_COLUMN,AX
JNZ END_END
CMP CURSOR_COLUMN,BL
JNZ END_END
CMP CURSOR_ROW,DL
MOV CURSOR_ROW,DL
JZ CTRL_END
END_END: MOV CURSOR_COLUMN,BL
RET
CTRL_HOME: MOV TOP_LINE,0
MOV CURSOR_ROW,0
MOV CURSOR_COLUMN,0
MOV START_COLUMN,0
RET
CTRL_END: MOV AX,LONGEST_LINE
MOV BX,COLUMNS
SUB AX,BX
JNS GOT_END2
XOR AX,AX
GOT_END2: MOV START_COLUMN,AX
DEC BX
MOV CURSOR_COLUMN,BL
MOV CURSOR_ROW,DL
MOV AX,LISTING_LEN
DEC AX
MUL CX
MOV DI,LAST_LINE
SUB DI,AX
JNB CTRL_END_END
XOR DI,DI
CTRL_END_END: MOV TOP_LINE,DI
RET
;----------------------------------------------;
DISP_DISPLAY: PUSH DS
PUSH ES
PUSH BP
MOV BP,TOP_LINE
MOV ES,INDEX_SEG
MOV CX,LISTING_LEN
MOV DI,CRT_WIDTH
NEXT_DISP: PUSH CX
PUSH DI
MOV CX,CS:COLUMNS
MOV DS,ES:SEG_PTR[BP]
MOV SI,ES:OFF_PTR[BP]
MOV BX,ES:TEXT_LEN[BP]
MOV AX,CS:START_COLUMN
MOV CS:DISPLAY_COLUMN,AX
ADD SI,AX
SUB BX,AX
JNC NEXT_DISP2
XOR BX,BX
NEXT_DISP2: MOV CS:DISPLAY_TEXT,BX
NEXT_DISP3: CMP CS:DISPLAY_TEXT,0
JZ PAD_LINE
CMP BP,CS:LAST_LINE
JA PAD_LINE
MOV BH,CS:COLOR.W
CMP BP,CS:MARK_INDEX
JNZ GET_BYTE
MOV AX,CS:DISPLAY_COLUMN
CMP AX,CS:MARK_LEFT
JB GET_BYTE
CMP AX,CS:MARK_RIGHT
JA GET_BYTE
MOV BH,CS:COLOR.C
GET_BYTE: LODSB
CALL WRITE_SCREEN
DEC CS:DISPLAY_TEXT
INC CS:DISPLAY_COLUMN
LOOP NEXT_DISP3
JMP SHORT DISPLAY_LOOP
PAD_LINE: MOV BH,CS:COLOR.W
CMP BP,CS:MARK_INDEX
JNZ WRITE_SPACE
MOV AX,CS:DISPLAY_COLUMN
CMP AX,CS:MARK_LEFT
JB WRITE_SPACE
CMP AX,CS:MARK_RIGHT
JA WRITE_SPACE
MOV BH,CS:COLOR.C
WRITE_SPACE: MOV AL,SPACE
CALL WRITE_SCREEN
INC CS:DISPLAY_COLUMN
LOOP PAD_LINE
DISPLAY_LOOP: ADD BP,SIZE INDEX_REC
POP DI
ADD DI,CS:CRT_WIDTH
POP CX
DEC CX
JZ DISPLAY_END
JMP NEXT_DISP
DISPLAY_END: POP BP
POP ES
POP DS
RET
;----------------------------------------------;
; OUTPUT: CF=1 if failed; SI-> Error message.
READ_FILE: CALL MENU_OFFSET
MOV BH,COLOR.B
MOV SI,OFFSET LOADING_FILE
CALL WRITE_STRING
CALL DOS_CURSOR
MOV DX,FILENAME
MOV AX,3D00H
INT 21H
MOV SI,OFFSET FILE_NOT_FOUND
JC READ_FILE_END
MOV BX,AX
READ_FILE2: PUSH DS
CMP STDIN_FLAG,1
JZ READ_FILE3
MOV AX,4400H ;Device info.
INT 21H
TEST DX,10000000B
JZ READ_FILE3
STC
JMP SHORT READ_CLOSE
READ_FILE3: MOV BP,TEXT_SEG
JMP SHORT NEXT_READ2
NEXT_READ: ADD BP,READ_SIZE SHR 4
NEXT_READ2: CMP BP,CS:MEM_TOP_SEG
JA READ_FULL
MOV CX,READ_SIZE
JNZ READ
MOV CX,CS:MEM_TOP_OFF
READ: XOR DX,DX
MOV DS,BP
MOV AH,3FH
INT 21H
MOV SI,OFFSET READ_FAIL
JC READ_CLOSE
OR AX,AX
JZ READ_CLOSE
CMP AX,READ_SIZE
JZ NEXT_READ
CMP CX,AX
JNZ READ_CLOSE
READ_FULL: MOV SI,OFFSET NOT_ENOUGH
STC
READ_CLOSE: MOV CS:EOF_SEG,BP
MOV CS:EOF_OFF,AX
PUSHF
MOV AH,3EH
INT 21H
POPF
POP DS
READ_FILE_END: PUSHF
CALL CLEAR_KEY
POPF
RET
;--------------------------------------------------------;
; OUTPUT: CF=1 if too many lines; SI-> Error message.
INDEX: PUSH DS
PUSH ES
MOV LONGEST_LINE,0
MOV BX,EOF_SEG
MOV DX,EOF_OFF
MOV ES,INDEX_SEG
XOR DI,DI
MOV BP,TEXT_SEG
MOV DS,BP
XOR SI,SI
NEXT_INDEX: MOV ES:OFF_PTR[DI],SI
MOV ES:SEG_PTR[DI],BP
XOR CX,CX ;Line length.
NEXT_BYTE: CMP SI,READ_SIZE
JB CK_END
ADD BP,READ_SIZE SHR 4
MOV DS,BP
SUB SI,READ_SIZE
CK_END: CMP SI,DX
JNZ READ_BYTE
CMP BP,BX
JNZ READ_BYTE
OR CX,CX
JNZ STORE_LAST
SUB DI,SIZE INDEX_REC
JMP SHORT INDEX_END
STORE_LAST: MOV ES:TEXT_LEN[DI],CX
MOV ES:LINE_LEN[DI],CX
JMP SHORT INDEX_END
READ_BYTE: LODSB
CMP AL,CR
JZ LINE_END2
CMP AL,CTRL_Z
JZ NEXT_BYTE
INC CX
CMP CX,LINE_MAX
JNZ NEXT_BYTE
MOV SI,OFFSET LINE_TOO_LONG
STC
JMP SHORT INDEX_END
LINE_END2: MOV ES:TEXT_LEN[DI],CX
CMP CX,CS:LONGEST_LINE
JBE CK_LEN
MOV CS:LONGEST_LINE,CX
CK_LEN: INC CX
CMP SI,DX
JNZ CK_LF
CMP BP,BX
JZ STORE_LEN
CK_LF: CMP BYTE PTR [SI],LF
JNZ CK_CTRL_Z
INC CX
INC SI
CK_CTRL_Z: CMP SI,DX
JNZ CK_CTRL
CMP BP,BX
JZ STORE_LEN
CK_CTRL: CMP BYTE PTR [SI],CTRL_Z
JNZ STORE_LEN
INC CX
INC SI
STORE_LEN: MOV ES:LINE_LEN[DI],CX
ADD DI,SIZE INDEX_REC
JBE TOO_MANY
JMP NEXT_INDEX
TOO_MANY: MOV SI,OFFSET TOO_MANY_LINES
STC
INDEX_END: POP ES
POP DS
MOV LAST_LINE,DI
RET
;----------------------------------------------;
VIDEO_SETUP: PUSH ES
MOV AX,500H ;Make sure active page is zero.
INT 10H
MOV AX,40H ;Point to the ROM BIOS data area
MOV ES,AX
MOV AX,ES:CRT_COLS
MOV COLUMNS,AX
SHL AX,1
MOV CRT_WIDTH,AX
MOV AX,ES:[4EH]
MOV CRT_START,AX
MOV AX,ES:[63H]
ADD AX,6
MOV CX,0B000H
CMP AX,3BAH
JZ STORE_SEG
ADD CX,800H
STORE_SEG: MOV STATUS_REG,AX
MOV VIDEO_SEG,CX
MOV SI,OFFSET MONO_ATTR
MOV AL,ES:CRT_MODE ;Retrieve current video mode.
CMP AL,7 ;Is it mono mode?
JZ GET_ROWS ;If yes, continue.
CMP AL,2 ;Is it BW80?
JZ GET_ROWS ;If yes, continue.
MOV SI,OFFSET COLOR_ATTR
CMP AL,3 ;Is it mode CO80?
JZ GET_ROWS ;If yes, continue.
MOV AX,3 ;Else, change video mode to CO80.
INT 10H
GET_ROWS: XOR BH,BH
MOV DL,24
MOV AX,1130H
INT 10H
MOV ROWS,DL ;Store rows.
SUB DL,2
XOR DH,DH
MOV LISTING_LEN,DX
POP ES
MOV DI,OFFSET COLOR
MOV CX,SIZE COLOR_ATTRIBS
REP MOVSB
;----------------------------------------------;
DISPLAY_SETUP: CALL CLS ;Clear screen.
CMP BORDER_FLAG,1
JZ DO_COPYRIGHT
MOV BL,COLOR.W ;Turn on border.
AND BL,7
XOR BH,BH
MOV AH,0BH
INT 10H
DO_COPYRIGHT: XOR AX,AX
CALL CALC_ADDR
INC DI
INC DI
MOV SI,OFFSET COPYRIGHT ;Point to copyright message.
MOV BH,COLOR.B ;Use header attribute.
CALL WRITE_STRING ;And display it.
MOV AL,BOX
CALL WRITE_SCREEN
MOV AL,SPACE
CALL WRITE_SCREEN
INC SI ;Bump pointer past LF
CALL WRITE_STRING ; and display rest of header.
RET
;----------------------------------------------;
DISPLAY_MENU: CALL MENU_OFFSET
PUSH DI
MOV BH,COLOR.B
MOV SI,OFFSET MENU
CALL WRITE_STRING
MOV AL,LINES_PER_REC
ADD AL,"1"
CALL WRITE_SCREEN
CALL WRITE_STRING
MOV AL,CURRENT_KEY
ADD AL,"1"
CALL WRITE_SCREEN
CALL GET_PRIORITY
CALL WRITE_STRING
MOV CX,SI
CALL DISP_ASCEND
MOV SI,CX
;---------------
POP DI
ADD DI,CRT_WIDTH
CALL WRITE_STRING
MOV CX,SI
CALL DISP_ALPHA
MOV SI,CX
CALL WRITE_STRING
CALL DISP_TYPE
MOV SI,OFFSET BLOCK_START
CMP CL,BLOCK_TYPE
JZ DISP_F10
MOV SI,OFFSET LINE_POS_MSG
CMP CL,LINE_TYPE
JZ DISP_F10
MOV SI,OFFSET SPACES
CMP CL,WORD_TYPE
JNZ DISP_F10
MOV SI,OFFSET WORD_POS_MSG
CALL WRITE_STRING
CALL DISP_WORD
DISP_F10: CALL WRITE_STRING
MOV SI,OFFSET ESC_MSG
CALL WRITE_STRING
RET
;----------------
DISP_TYPE: MOV SI,OFFSET FIELD_OFFSET
MOV CL,KEYS.KEY_FIELD[BP]
XOR CH,CH
ADD SI,CX
ADD SI,CX
MOV SI,[SI]
CALL WRITE_STRING
RET
DISP_ASCEND: MOV SI,OFFSET ASCENDING
CMP KEYS.SORT_DIRECTION[BP],ASCEND
JZ DISP_DIR
MOV SI,OFFSET DESCENDING
DISP_DIR: CALL WRITE_STRING
RET
DISP_ALPHA: MOV SI,OFFSET ALPHANUMERIC
CMP KEYS.KEY_TYPE[BP],ALPHA_TYPE
JZ DISP_KEY_TYPE
MOV SI,OFFSET NUMERIC
DISP_KEY_TYPE: CALL WRITE_STRING
RET
DISP_WORD: MOV CL,KEYS.WORD_POS[BP]
MOV AL,"+"
OR CL,CL
JNS DISP_SIGN
MOV AL,"-"
NEG CL
DISP_SIGN: CALL WRITE_SCREEN
MOV AL,CL
ADD AL,"1" - 1
CALL WRITE_SCREEN
RET
DISP_LINE: MOV AX,KEYS.LINE_INDEX[BP]
PUSH BX
CALL CALC_ROW
POP BX
DIV CX
ADD AL,"1"
CALL WRITE_SCREEN
RET
DISP_BLOCK: MOV AX,KEYS.BLOCK_BEG[BP]
INC AX
JZ DISP_BLOCK_END
PUSH DI
CALL DEC_OUTPUT
POP DI
ADD DI,2 * 5
PUSH DI
MOV AX,KEYS.BLOCK_LEN[BP]
CALL DEC_OUTPUT
POP DI
ADD DI,2 * 5
MOV AX,KEYS.BLOCK_INDEX[BP]
PUSH BX
CALL CALC_ROW
POP BX
DIV CX
ADD AL,"1"
CALL WRITE_SCREEN
DISP_BLOCK_END:RET
;-------------------------------------;
; INPUT: AX = number.
DEC_OUTPUT: MOV SI,10 ;Convert to decimal.
XOR CX,CX ;Zero in counter.
NEXT_COUNT: XOR DX,DX
DIV SI
ADD DL,'0' ;Convert to ASCII.
PUSH DX ;Save results.
INC CX ;Also increment count.
CMP AX,0 ;Are we done?
JNZ NEXT_COUNT
NEXT_NUMBER: POP AX ;Retrieve numbers.
CALL WRITE_SCREEN ;And write them.
LOOP NEXT_NUMBER
RET
;-----------------
GET_PRIORITY: PUSH AX
MOV AL,SIZE SORT_KEY
MUL CURRENT_KEY
MOV BP,AX
POP AX
RET
;----------------------------------------------;
;INPUT: CX=char count; AX=character
REPEAT_CHAR: PUSH AX
CALL WRITE_SCREEN
POP AX
LOOP REPEAT_CHAR
RET
;----------------------------------------------;
; INPUT: AX = Starting line; OUTPUT: DI = Video address.
CALC_ADDR: MUL CRT_WIDTH
ADD AX,CRT_START
MOV DI,AX
RET
;----------------------------------------------;
; INPUT: AL = character to write; BH = attribute.
WRITE_SCREEN: PUSH ES
MOV ES,CS:VIDEO_SEG ;Point to screen segment.
MOV DX,CS:STATUS_REG ;Retrieve status register.
MOV BL,AL ;Store character in BL.
HORZ_RET: IN AL,DX ;Get status.
RCR AL,1 ;Is it low?
JC HORZ_RET ;If not, wait until it is.
CLI ;No more interrupts.
HWAIT: IN AL,DX ;Get status.
RCR AL,1 ;Is it high?
JNC HWAIT ;If no, wait until it is.
MOV AX,BX ;Retrieve character; now it's OK
STOSW ; to write to screen buffer.
STI ;Interrupts back on.
POP ES
RET ;Return
;----------------------------------------------;
; INPUT: SI -> to string to display; DI -> where to display it.
; Entry point is WRITE_STRING.
WRITE_IT: CALL WRITE_SCREEN ;Write a character.
WRITE_STRING: LODSB ;Retrieve a character.
CMP AL,CR ;Keep writing until a carriage
JA WRITE_IT ; return or zero encountered.
RET
;----------------------------------------------;
CLEAR_MENU: CALL MENU_OFFSET ;Calculate menu screen offset.
PUSH DI
MOV BH,COLOR.B ;Menu attribute.
MOV CX,CRT_WIDTH ;Blank out the two lines of menu.
NEXT_MENU: MOV AL,SPACE
CALL WRITE_SCREEN
LOOP NEXT_MENU
POP DI
RET
;----------------------------------------;
; OUTPUT: DI -> Screen offset for menu. ;
;----------------------------------------;
MENU_OFFSET: MOV AL,ROWS
DEC AL
XOR AH,AH
CALL CALC_ADDR
RET
;----------------------------------------------;
CLS: MOV BH,COLOR.B ;Normal attribute.
CLS2: XOR CX,CX ;Top left corner.
MOV DL,BYTE PTR COLUMNS
DEC DL
MOV DH,ROWS
MOV AX,600H ;Scroll active page.
PUSH BP
INT 10H
POP BP
RET
;----------------------------------------------;
CLOSE_SCREEN: PUSH AX
CALL CK_MODIFIED
MOV BH,SCREEN_COLOR
CALL CLS2
CMP BORDER_FLAG,1
JZ PLACE_CURSOR
XOR BX,BX
MOV AH,0BH
INT 10H
PLACE_CURSOR: XOR DX,DX
CALL SET_CURSOR
POP AX
RET
;----------------------------------------------;
BEEP: MOV BX,NOTE ;Tone frequency divisor.
MOV DX,12H
XOR AX,AX
DIV BX
MOV BX,AX ;8253 countdown.
CALL DELAY ;Wait till clock rolls over.
MOV AL,0B6H ;Channel 2 speaker functions.
OUT 43H,AL ;8253 Mode Control.
JMP $+2 ;IO delay.
MOV AX,BX ;Retrieve countdown.
OUT 42H,AL ;Channel 2 LSB.
JMP $+2
MOV AL,AH ;Channel 2 MSB.
OUT 42H,AL
IN AL,61H ;Port B.
OR AL,3 ;Turn on speaker.
JMP $+2
OUT 61H,AL
CALL DELAY ;Delay one second.
IN AL,61H ;Get Port B again.
AND AL,NOT 3 ;Turn speaker off.
JMP $+2
OUT 61H,AL
RET ;Done.
;-----------------------------;
DELAY: PUSH DS ;Preserve data segment.
MOV AX,40H ;Point to BIOS data segment.
MOV DS,AX
MOV AX,DS:[6CH] ;Retrieve timer low.
NEXT_BEEP: MOV DX,DS:[6CH] ;Retrieve timer low.
CMP DX,AX ;Have we timed out?
JZ NEXT_BEEP ;If not, wait until second up.
POP DS ;Restore data segment.
RET
;*************LINE EDITOR**********************;
LINE_START DW ?
LINE_END DW ?
;INPUT: DI=buffer position; LINE_START, LINE_END.
;OUTPUT: AL=char. AH=scan code. CY=1 if Esc pressed.
EDITOR: CALL GETKEY
XCHG AL,AH
JNC DO_EDIT
JMP EDITOR_END
DO_EDIT: MOV BX,DI
MOV DX,LINE_START
MOV CX,LINE_END
CMP AH,ENTER_SCAN
JNZ CK_RIGHT
JMP EDITOR_DONE
CK_RIGHT: CMP AX,RIGHT_SCAN SHL 8
JNZ CK_LEFT
CMP DI,CX
JZ EDITOR_DONE
CMP BYTE PTR [DI],SPACE
JZ EDITOR_DONE
INC DI
CK_LEFT: CMP AX,LEFT_SCAN SHL 8
JNZ CK_BS
CMP DI,DX
JZ EDITOR_DONE
DEC DI
CK_BS: CMP AH,BS_SCAN
JNZ CK_DEL
CMP DI,DX
JZ EDITOR_DONE
DEC DI
CALL CK_INSERT
JNZ DO_DEL
MOV BYTE PTR [DI],SPACE
JMP SHORT EDITOR_CHANGE
CK_DEL: CMP AX,DEL_SCAN SHL 8
JNZ CK_HOME
DO_DEL: PUSH DI
MOV SI,DI
INC SI
DEC CX
SUB CX,DI
JS DEL_END
REP MOVSB
MOV BYTE PTR [DI],SPACE
DEL_END: POP DI
JMP SHORT EDITOR_CHANGE
CK_HOME: CMP AX,HOME_SCAN SHL 8
JNZ CK_END2
MOV DI,DX
CK_END2: CMP AX,END_SCAN SHL 8
JNZ CK_ASCII
NEXT_CK_END2: CMP DI,CX
JZ EDITOR_DONE
CMP BYTE PTR [DI],SPACE
JZ EDITOR_DONE
INC DI
JMP NEXT_CK_END2
CK_ASCII: CMP AL,SPACE
JB EDITOR_DONE
CMP AL,127
JA EDITOR_DONE
CMP DI,LINE_END
JAE EDITOR_DONE
CALL CK_INSERT
JNZ DO_INSERT
JMP SHORT EDITOR_DONE1
DO_INSERT: PUSH DI
DEC CX
MOV DI,CX
SUB CX,BX
JZ EDITOR_DONE2
MOV SI,DI
DEC SI
STD
REP MOVSB
CLD
EDITOR_DONE2: POP DI
EDITOR_DONE1: STOSB
EDITOR_CHANGE: ; MOV MODIFY_FLAG,1
EDITOR_DONE: CLC
EDITOR_END: RET
;--------------------------
CK_INSERT: PUSH DS
MOV DX,40H
MOV DS,DX
MOV DL,DS:[17H]
TEST DL,80H ;Insert
POP DS
RET
;----------------------------------------------;
DOS_CURSOR: MOV DX,200H ;Put cursor on screen in case
JMP SHORT SET_CURSOR ; of critical error like drive
; drive door open.
HIDE_CURSOR: MOV DH,ROWS ;Retrieve CRT rows.
INC DH ;Move one line below off screen.
XOR DL,DL ;Column zero.
SET_CURSOR: PUSH BX
XOR BH,BH ;Page zero.
MOV AH,2 ;Set cursor position.
INT 10H
POP BX
RET
;----------------------------------------------;
; INPUT: DI -> Valid scan codes table; CX = Length of table
; OUTPUT: AL=Scan code; AH=Char; CF=1 if Esc pressed.
DISPATCH: CALL GETKEY
PUSH AX
JC DISPATCH_END
CMP AH,CR
JZ DISPATCH_END
MOV BX,CX
MOV DX,DI
ADD DX,CX
REPNZ SCASB
JNZ NO_DISPATCH
GOT_DISPATCH: SUB BX,CX
DEC BX
SHL BX,1
ADD BX,DX
CALL GET_PARAMS
DO_DISPATCH: CALL [BX] ;Process the command.
NO_DISPATCH: CLC
DISPATCH_END: POP AX
RET
;----------------------------------------------;
GET_PARAMS: MOV DI,TOP_LINE
MOV CX,SIZE INDEX_REC
MOV AX,LISTING_LEN
DEC AX
MUL CL
MOV SI,AX
ADD SI,DI
CMP SI,LAST_LINE
JBE CALC_LINE
MOV SI,LAST_LINE
CALC_LINE: MOV AX,SI
SUB AX,DI
DIV CL
XOR AH,AH
MOV DX,AX
RET
;----------------------------------------------;
GETKEY: MOV AH,0 ;Wait for next keyboard input.
INT 16H
XCHG AH,AL
CMP AL,ESC_SCAN
STC
JZ GETKEY_END
CLC
GETKEY_END: RET
CK_KEY: MOV AH,1 ;Is there a keystroke available.
INT 16H
RET
CLEAR_IT: CALL GETKEY ;Read keystrokes until buffer
CLEAR_KEY: CALL CK_KEY ; empty.
JNZ CLEAR_IT
RET
;----------------------------------------------;
WRITE_TTY: MOV AH,0EH
INT 10H
RET
;----------------------------------------------;
PRINT_STRING: MOV AH,9 ;Print string via DOS.
INT 21H
RET
;----------------------------------------------;
EVEN
STACK_POINTER = $ + 256
_TEXT ENDS
END START